# docbook2dict2013.py
# -*- coding: utf-8 -*-
"""Reformat a dicom dictionary PS3.6 docbook file (from e.g. standards docs) to Python syntax

   Write the DICOM dictionary elements as:
   tag: (VR, VM, description, keyword, is_retired)
   in python format
   
   Also write the repeating groups or elements (e.g. group "50xx")
   as masks that can be tested later for tag lookups that didn't work
"""
#
# Copyright 2011-2012, Darcy Mason
# This file is part of pydicom, released under an MIT licence.
# See license.txt file for more details.

part6_filename = "part06.xml"
part7_filename = "part07.xml"
pydict_filename = "_dicom_dict.py"
main_dict_name = "DicomDictionary"
mask_dict_name = "RepeatersDictionary"

def write_dict(f, dict_name, attributes, tagIsString):
    if tagIsString:
        entry_format = """'{Tag}': ('{VR}', '{VM}', "{Name}", '{Retired}', '{Keyword}')"""
    else:
        entry_format = """{Tag}: ('{VR}', '{VM}', "{Name}", '{Retired}', '{Keyword}')"""
    f.write("\n%s = {\n    " % dict_name)
    f.write(",\n    ".join(entry_format.format(**attr) for attr in attributes))
    f.write("\n}\n")

def parse_docbook_table(book, caption, empty_field_name="Retired"):
    registry = next(t for t in book.findAll("table") if t.caption.text == caption)
    fields = [x.text.strip() for x in registry.thead.tr.childGenerator() if x.__class__ is bs4.element.Tag]
    fields = [x if x != "" else empty_field_name for x in fields]
    def parserow(fields, row):
        return {k:v for k,v in zip(fields, (x.text.strip().replace(u"\u200b","") for x in row.findAll("td")))}
    attrs = [parserow(fields, row) for row in registry.tbody.findAll("tr")]
    return attrs


if __name__ == "__main__":
    import bs4 # xml parsing module
    import os

    part6book = bs4.BeautifulSoup(file(part6_filename))
    part7book = bs4.BeautifulSoup(file(part7_filename))
    attrs = parse_docbook_table(part6book, "Registry of DICOM Data Elements")
    attrs += parse_docbook_table(part6book, "Registry of DICOM File Meta Elements")
    attrs += parse_docbook_table(part6book, "Registry of DICOM Directory Structuring Elements")

    command_attrs = parse_docbook_table(part7book, "Command Fields (Part 1)")
    for attr in command_attrs:
        attr["Name"] = attr["Message Field"]
        attr["Retired"] = ""
    attrs += command_attrs        

    retired_command_attrs = parse_docbook_table(part7book, "Retired Command Fields")
    for attr in retired_command_attrs:
        attr["Name"] = attr["Message Field"]
        attr["Retired"] = "Retired"
    attrs += retired_command_attrs

    attrs = sorted(attrs, key=lambda x: x["Tag"])

    main_attributes = []
    mask_attributes = []
    for attr in attrs:
        group, elem = attr["Tag"][1:-1].split(",")
        if attr["VR"] == "See Note": # used with some delimiter tags
            attr["VR"] = "NONE"      # to be same as '08 dict in pydicom
        
        if attr["Retired"] == "DICONDE" or attr["Retired"] == "DICOS":
            attr["Retired"] = ""

        attr["Name"] = attr["Name"].replace(u"µ", "u") # replace micro symbol

        if attr["Retired"] == "See Note":
            attr["Retired"] = ""

        if attr["Retired"].endswith(" - See Note"):
            attr["Retired"] = attr["Retired"][:attr["Retired"].find(" - See Note")]

        attr["Retired"] = attr["Retired"].replace("RET", "Retired")
		
        attr["VM"] = attr["VM"].replace(" or ", " ")

        # If blank (e.g. (0018,9445) and (0028,0020)), then add dummy vals
        if attr["VR"] == '' and attr["VM"] == '' and attr["Retired"] != "":
            attr["VR"] = 'OB'
            attr["VM"] = '1'
            attr["Name"] = "Retired-blank"
        
        # Handle retired "repeating group" tags e.g. group "50xx"
        if "x" in group or "x" in elem:
            attr["Tag"] = group + elem # simple concatenation
            mask_attributes.append(attr)
        else:
            attr["Tag"] = "0x%s%s" % (group, elem)
            main_attributes.append(attr)

    # wb for producing unix line endings even on windows
    py_file = file(pydict_filename, "wb")
    py_file.write("# %s\n" % pydict_filename)
    py_file.write('"""DICOM data dictionary auto-generated by %s"""\n' % os.path.basename(__file__))
    py_file.write('from __future__ import absolute_import\n')
    write_dict(py_file, main_dict_name, main_attributes, tagIsString=False)
    write_dict(py_file, mask_dict_name, mask_attributes, tagIsString=True)

    py_file.close()

    print "Finished creating python file %s containing the dicom dictionary" % pydict_filename
    print "Wrote %d tags" % (len(main_attributes)+len(mask_attributes))
